import wx
import wx.grid

import calendar
import datetime
import time

from talkToGoogle import *

# leave monthNames[0] and monthColors[0] empty to index such that jan=1, feb=2, etc.
monthNames = ['','January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
monthColors = [(),
               (255, 255, 255), (23, 130, 217), (23, 190, 100),
               (109, 41, 222), (222, 232, 32), (132, 241, 22),
               (0, 102, 0), (179, 89, 0), (128, 64, 0),
                (255, 128, 0), (182, 67, 33), (206, 0, 0)]

dayLabels = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
dateLabels = ['', '', '', '', '', '', '']

toggleColors = [(187, 28, 39), (154, 230, 132), (95, 185, 201)]

temp_list = list()

google_interface = talkToGoogle()


# does stuff related to displaying the month and date in the gui
class Calendar():
    def __init__(self):
        # month, day, and year are numbers in the form ##/##/####
        self.month = time.localtime()[1]
        self.day = time.localtime()[2]
        self.year = time.localtime()[0]

    def query(self, week_offset):
        offset_day = self.day + week_offset*7
        
        # determine what the next and previous months are
        next_month = (self.month % 12) + 1
        if self.month - 1 != 0:
            prev_month = self.month - 1
        else:
            prev_month = 12

        # determine if we are at the edge of a year
        if next_month == 1:
            next_year = self.year + 1
        else:
            next_year = self.year
        if prev_month == 12:
            prev_year = self.year - 1
        else:
            prev_year = self.year
        

        # number of days in month and which day of the week was the first day of the month
        month_range = calendar.monthrange(self.year, self.month)[1]
        first_of_month = calendar.monthrange(self.year, self.month)[0]

        # current day (e.g. mon = 0, tues = 1, etc.)
        current_day = datetime.date.weekday(datetime.date(self.year, self.month, self.day))

        # months covered by current week
        months = [self.month]

        # figure out dateLabels
        for i in range(7):
            dom = offset_day - current_day + i
            if dom <= 0:
                months = [prev_month, self.month]
                dom = calendar.monthrange(prev_year, prev_month)[1] + dom
            elif dom > month_range:
                months = [self.month, next_month]
                dom = dom - month_range

            dateLabels[i] = '\n%i' % dom

        # week is entirely in next month
        if offset_day - month_range - current_day > 1:
            months = [next_month]

        # week is entirely in previous month
        # note: the second comparison looks to see if going to the end of the week (in 6 - current_days days)
        #       will carry you into the following month 
        elif offset_day < 0 and 6 - current_day < abs(offset_day):
            months = [prev_month]

        return months, self.year


class SetupTable(wx.grid.PyGridTableBase):

    data = [('12:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''), ('1:00', '', '', '', '', '', '', ''),
            ('', '', '', '', '', '', '', ''), ('2:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''),
            ('3:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''), ('4:00', '', '', '', '', '', '', ''),
            ('', '', '', '', '', '', '', ''), ('5:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''),
            ('6:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''), ('7:00', '', '', '', '', '', '', ''),
            ('', '', '', '', '', '', '', ''), ('8:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''),
            ('9:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''), ('10:00', '', '', '', '', '', '', ''),
            ('', '', '', '', '', '', '', ''), ('11:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''),
            ('12:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''), ('1:00', '', '', '', '', '', '', ''),
            ('', '', '', '', '', '', '', ''), ('2:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''),
            ('3:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''), ('4:00', '', '', '', '', '', '', ''),
            ('', '', '', '', '', '', '', ''), ('5:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''),
            ('6:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''), ('7:00', '', '', '', '', '', '', ''),
            ('', '', '', '', '', '', '', ''), ('8:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''),
            ('9:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', ''), ('10:00', '', '', '', '', '', '', ''),
            ('', '', '', '', '', '', '', ''), ('11:00', '', '', '', '', '', '', ''), ('', '', '', '', '', '', '', '')]

    def __init__(self):
        wx.grid.PyGridTableBase.__init__(self)

    def GetNumberRows(self):
        return len(self.data)

    def GetNumberCols(self):
        return len(self.data[0]) - 1

    def GetColLabelValue(self, col):
        return dayLabels[col] + dateLabels[col]

    def GetRowLabelValue(self, row):
        return self.data[row][0]


# need to refine class with an "init" function that loads in current week
# and an "update" function that can change the labels based on a week offset
class TestFrame(wx.Frame):
    
    authenticated = False
    
    week_offset = 0
    
    
    def __init__(self, parent):#, months):
        wx.Frame.__init__(self, parent, -1, "Calendar Desktop GUI", size=(680, 800))

        ''' set up splitter window and frame panels'''
        self.sp = wx.SplitterWindow(self)

        self.p1 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)
        self.p2 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)
        self.p1.SetBackgroundColour((120, 120, 120))
        self.p2.SetBackgroundColour((120, 120, 120))
        
        self.p1.Hide()
        self.p2.Hide()

        self.sp.Initialize(self.p1)

        self.sp.SplitHorizontally(self.p1, self.p2, 150)
        ''' '''


        ''' bottom panel '''
        self.p2.grid = wx.grid.Grid(self.p2, size=(670,510))
        self.p2.grid.SetTable(SetupTable())

        self.p2.grid.SetSelectionBackground((120, 120, 120))

        self.p2.grid.DisableDragColSize()
        self.p2.grid.DisableDragRowSize()
        self.p2.grid.DisableCellEditControl()

        #wx.grid.EVT_GRID_CELL_LEFT_CLICK(self, self.CellClick)
        wx.grid.EVT_GRID_RANGE_SELECT(self, self.RangeSelect)

        self.p2.prev_week = wx.Button(self.p2, -1, "< <", (170, 540))
        self.p2.next_week = wx.Button(self.p2, -1, "> >", (440, 540))
        self.p2.save_events = wx.Button(self.p2, -1, "Save", (300, 540))
        self.p2.save_events.Show(False)

        self.Bind(wx.EVT_BUTTON, self.PrevWeek, self.p2.prev_week)
        self.Bind(wx.EVT_BUTTON, self.NextWeek, self.p2.next_week)
        self.Bind(wx.EVT_BUTTON, self.SaveEvents, self.p2.save_events)
        ''' '''


        ''' top panel '''
        self.MonthDisplay()
        
        self.p1.uname = wx.TextCtrl(self.p1, -1, "username", (540, 20), style=wx.TE_LINEWRAP)
        self.p1.passwd = wx.TextCtrl(self.p1, -1, "password", (540, 50), style=wx.TE_PASSWORD)

        self.p1.login = wx.Button(self.p1, -1, "Login", (540, 80))
        self.p1.logout = wx.Button(self.p1, -1, "Logout", (540, 80))
        self.p1.logout.Show(False)

        self.Bind(wx.EVT_BUTTON, self.AttemptAuth, self.p1.login)
        self.Bind(wx.EVT_BUTTON, self.Logout, self.p1.logout)
        ''' '''

        self.ClearCellStates()

        

    def MonthDisplay(self):
        months, year = Calendar().query(self.week_offset)
        try:
            months_str = monthNames[months[0]] + " / " + monthNames[months[1]]
        except IndexError:
            months_str = monthNames[months[0]]
            
        str_length = len(months_str)

        font_size = 24
        month_font = wx.Font(font_size, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, u'Candara')

        self.p1.month = wx.StaticText(self.p1, -1, "%s" % (months_str), (0, 50), (680, 190), style=wx.ALIGN_CENTRE)
        self.p1.month.SetForegroundColour(monthColors[months[0]])
        self.p1.month.SetFont(month_font)
        self.p1.month.MoveXY(680/2 - str_length/2*font_size/2, 50)

        #self.p2.grid.Refresh()


    def DestroyMonthDisplay(self):
        self.p1.month.Destroy()

    def UserDisplay(self):
        user_str = 'Welcome, ' + google_interface.user_name

        str_length = len(user_str)

        font_size = 16
        user_font = wx.Font(font_size, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, u'Candara')

        self.p1.user = wx.StaticText(self.p1, -1, "%s" % (user_str), (0, 120), style=wx.ALIGN_CENTRE)
        #self.p1.month.SetForegroundColour()
        self.p1.user.SetFont(user_font)
        self.p1.user.MoveXY(680/2 - str_length/2*font_size/2, 100)

    def HideUserDisplay(self):
        self.p1.user.Show(False)
        

    def PrevWeek(self, event):
        if self.week_offset >= -1:
            self.week_offset -= 1
            self.p2.next_week.Show(True)
            
            Calendar().query(self.week_offset)
            self.DestroyMonthDisplay()
            self.MonthDisplay()
            self.LoadCellStates()

            if self.week_offset == -2:
                self.p2.prev_week.Show(False)

    def NextWeek(self, event):
        if self.week_offset <= 1:
            self.week_offset += 1
            self.p2.prev_week.Show(True)
            
            Calendar().query(self.week_offset)
            self.DestroyMonthDisplay()
            self.MonthDisplay()
            self.LoadCellStates()

            if self.week_offset == 2:
                self.p2.next_week.Show(False)

    def SaveEvents(self, event):
        months, year = Calendar().query(self.week_offset)
        current_month = months[0]


        delete_start_month = months[0]
        delete_end_month = months[-1]

        delete_start_year = year
        if delete_end_month == 1:
            delete_end_year = delete_start_year + 1
        else:
            delete_end_year = delete_start_year

        delete_start_day = int(dateLabels[0])
        if int(dateLabels[6])+1 < calendar.monthrange(delete_end_year, delete_end_month)[1]:
            delete_end_day = int(dateLabels[6])+1
        else:
            delete_end_day = 1
            delete_end_month = 1 + (delete_end_month % 12)
            if delete_end_month == 1:
                delete_end_year = delete_end_year + 1

        print 'Deleting Google events for current week view.'
        google_interface.removeRangeEvents(google_interface.user_name,
                                           timeToString(datetime.datetime(delete_start_year, delete_start_month, delete_start_day, 0, 0),4),
                                           timeToString(datetime.datetime(delete_end_year, delete_end_month, delete_end_day, 0, 0),4),
                                           'available')


        print 'Saving events for current week view.\n'
        
        # add events in blocks
        for col in range(7):
            first = -1
            save = False
            
            try:
                if int(dateLabels[col]) < int(dateLabels[col-1]):
                    current_month = months[1]
            except IndexError:
                pass

            # must handle case where the last row is 'available'
            for row in range(48):
                if temp_list[self.week_offset+2][col][row] == 'available':
                    if first < 0:
                        first = row
                    if row == 47:
                        last = 0
                        save = True
                elif temp_list[self.week_offset+2][col][row] == '' or temp_list[self.week_offset+2][col][row] == 'changed':
                    if first >= 0:
                        last = row
                        save = True

                if save == True:
                    start_day = int(dateLabels[col])
                    start_month = current_month
                    start_year = year
                    
                    if last == 0:
                        try:
                            end_day = int(dateLabels[col+1])
                            end_month = start_month
                            end_year = start_year
                        except IndexError:
                            if int(dateLabels[col])+1 < calendar.monthrange(self.year, self.month)[1]:
                                end_day = int(dateLabels[col])+1
                                end_month = start_month
                                end_year = year
                            else:
                                end_day = 1
                                end_month = 1 + (current_month % 12)
                                if end_month == 1:
                                    end_year = year + 1
                                else:
                                    end_year = year
                    else:
                        end_day = start_day
                        end_month = start_month
                        end_year = start_year
                        

                    
                    google_interface.addEvent(self.user,
                                              timeToString(datetime.datetime(start_year, start_month, start_day, first/2, (first%2) * 30), 4),
                                              timeToString(datetime.datetime(end_year, end_month, end_day, last/2, (last%2) * 30), 4),
                                              'available')

                    first = -1
                    last = -1
                    save = False

        self.LoadCellStates()


    def AttemptAuth(self, event):
        self.user = self.p1.uname.GetValue()
        pwd = self.p1.passwd.GetValue()

        self.authenticated = google_interface.authenticate(self.user, pwd)
        if self.authenticated:
            # show save button
            self.p2.save_events.Show(True)

            # hide login boxes/button
            self.p1.uname.Show(False)
            self.p1.passwd.Show(False)
            self.p1.login.Show(False)

            self.p1.logout.Show(True)

            self.UserDisplay()

            self.ClearCellStates()
            self.InitializeCellStates()
            self.LoadCellStates()
        else:
            msg = wx.MessageDialog(None, 'Incorrect user/password combination.', 'Try again', wx.OK)
            msg.ShowModal()
            msg.Destroy()
            

    def Logout(self, event):
        self.authenticated = google_interface.logout()

        self.p1.logout.Show(False)
        self.p2.save_events.Show(False)

        self.p1.uname.SetLabel('username')
        self.p1.passwd.SetLabel('password')

        self.p1.uname.Show(True)
        self.p1.passwd.Show(True)
        self.p1.login.Show(True)

        self.week_offset = 0
        Calendar().query(self.week_offset)
        self.HideUserDisplay()
        self.DestroyMonthDisplay()
        self.MonthDisplay()
        self.ClearCellStates()

    def ChangeCellState(self, row, col):
        if temp_list[self.week_offset+2][col][row] == 'work':
            pass
        elif temp_list[self.week_offset+2][col][row] == '' or temp_list[self.week_offset+2][col][row] == 'changed':
            temp_list[self.week_offset+2][col][row] = 'available'
            self.p2.grid.SetCellBackgroundColour(row, col, toggleColors[1])
        else:
            temp_list[self.week_offset+2][col][row] = 'changed'
            self.p2.grid.SetCellBackgroundColour(row, col, toggleColors[0])


    def LoadCellStates(self):
        for col in range(7):
            for row in range(48):
                if temp_list[self.week_offset+2][col][row] == 'work':
                    self.p2.grid.SetCellBackgroundColour(row, col, toggleColors[2])
                elif temp_list[self.week_offset+2][col][row] == 'available':
                    self.p2.grid.SetCellBackgroundColour(row, col, toggleColors[1])
                elif temp_list[self.week_offset+2][col][row] == 'changed':
                    self.p2.grid.SetCellBackgroundColour(row, col, toggleColors[0])
                else:
                    self.p2.grid.SetCellBackgroundColour(row, col, (255, 255, 255))

        self.p2.grid.ClearSelection()
        self.p2.grid.Refresh()

    def ClearCellStates(self):
        while len(temp_list) is not 0:
            temp_list.pop()
        
        # copy the weekly 7x48 event matrix 5 times (1 matrix per viewable week)
        for i in range(5):
            temp_list.append([['', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', ''],
                              ['', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', ''],
                              ['', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', ''],
                              ['', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', ''],
                              ['', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', ''],
                              ['', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', ''],
                              ['', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '',
                               '', '', '', '', '', '', '', '', '', '', '', '']])
        self.LoadCellStates()

    def InitializeCellStates(self):
        for i in range(-2, 3):
            months, year = Calendar().query(i)
            
            start_month = months[0]
            end_month = months[-1]

            start_year = year
            if end_month == 1:
                end_year = start_year + 1
            else:
                end_year = start_year

            start_day = int(dateLabels[0])
            if int(dateLabels[6])+1 < calendar.monthrange(end_year, end_month)[1]:
                end_day = int(dateLabels[6])+1
            else:
                end_day = 1
                end_month = 1 + (end_month % 12)
                if end_month == 1:
                    end_year = end_year + 1


            # load 'available' events from google into temp_list
            available_events = google_interface.acquireEmployeeEvents(self.user,
                                                       'available',
                                                       timeToString(datetime.datetime(start_year,start_month,start_day,0,0,0),4),
                                                       timeToString(datetime.datetime(end_year,end_month,end_day,0,0,0),4))

            for event in available_events:
                start = event[3][0]
                end = event[4][0]

                col = dateLabels.index('\n%i' % start.day)
                
                start_row = 2*start.hour + start.minute/30
                if end.hour == 0 and end.minute == 0:
                    end_row = 48
                else:
                    end_row = 2*end.hour + end.minute/30

                for row in range(start_row, end_row):
                    temp_list[i+2][col][row] = 'available'


            # load 'work' events from google into temp_list
            work_events = google_interface.acquireEmployeeEvents(self.user,
                                                       'work',
                                                       timeToString(datetime.datetime(start_year,start_month,start_day,0,0,0),4),
                                                       timeToString(datetime.datetime(end_year,end_month,end_day,0,0,0),4))

            for event in work_events:
                start = event[3][0]
                end = event[4][0]

                col = dateLabels.index('\n%i' % start.day)
                
                start_row = 2*start.hour + start.minute/30
                if end.hour == 0 and end.minute == 0:
                    end_row = 48
                else:
                    end_row = 2*end.hour + end.minute/30

                for row in range(start_row, end_row):
                    temp_list[i+2][col][row] = 'work'

        # reset week view to current week
        Calendar().query(0)
                    
                
    # this function causes highlighting to anchor at cell (0, 0). even an empty
    # function definition will cause this behavior.
    #def CellClick(self, event):
    #    self.ChangeCellColor(event.GetRow(), event.GetCol())

    #    if event.Selecting:
    #        self.p2.grid.ClearSelection()
            
    #    self.p2.grid.Refresh()
        

    def RangeSelect(self, event):
        # change the color and state of the selected cells
        point1, point2 = event.GetTopLeftCoords()
        point3, point4 = event.GetBottomRightCoords()
        

        # test this to prevent the initial click from registering as points a and b
        if self.p2.grid.IsInSelection(point1, point2) and self.p2.grid.IsInSelection(point3, point4):# and self.authenticated:
            for row in xrange(point1, point3+1):
                for col in xrange(point2, point4+1):
                    self.ChangeCellState(row, col)
            
        self.p2.grid.Refresh()

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = TestFrame(None)
    frame.Show(True)
    app.SetTopWindow(frame)
    app.MainLoop()
